/*
 *  BMP.h
 *  SCMS
 *
 *  Created by poiuy_qwert on 21/07/09.
 *
 */

#pragma once

#include "Palettes.h"
#include "Exception.h"
#include "Pack.h"
#include "Logging.h"

#include <list>
#include <fstream>
#include <cstring>

using namespace std;

namespace BMP_COMPRESSION {
	enum Enum {
		NONE,
		RLE8,
		/*RLE4,
		BITFIELDS,
		JPEG,
		PNG*/
	};
}

#pragma pack(1)
struct BMP_HEADER {
	char sign[2];
	unsigned long fileSize;
	short extra[2];
	unsigned long dataOffset;
};

struct BMP_V3_INFO_HEADER {
	long width, height;
	unsigned short planes, bitsPerPixel;
	BMP_COMPRESSION::Enum compression;
	unsigned long dataSize, horizontalResolution, verticalResolution, colors, importantColors;
};
#pragma pack(0)

class BMP {
	Palette *palette;
	unsigned char* planes;
	int width, height;
public:
	BMP()
		: palette(NULL),planes(NULL),width(0),height(0) {}
	BMP(const char *filename)
		: palette(NULL),planes(NULL),width(0),height(0)
		{ this->open_file(filename); }
	BMP(const char *buffer, int size)
		: palette(NULL),planes(NULL),width(0),height(0)
		{ this->open_data(buffer, size); }
	BMP(const unsigned char *plane, int width, int height, Palette *palette)
		: palette(palette),planes(NULL),width(0),height(0)
		{ this->set_plane(plane, width, height); }
	~BMP()
		{ this->close(); }

	void open_file(const char *filename);
	void open_data(const char *buffer, int size);
	void save_file(const char *filename, BMP_COMPRESSION::Enum compression = BMP_COMPRESSION::NONE);
	char* save_data(int &size, BMP_COMPRESSION::Enum compression = BMP_COMPRESSION::NONE);
	
	static unsigned char* rle8_decompress(const unsigned char *cmd, int size, int width, int height);
	static unsigned char* rle8_compress(const unsigned char *planes, int &size, int width, int height);
	int get_width()
		{ return this->width; }
	int get_height()
		{ return this->height; }
	unsigned char* get_planes()
		{ return this->planes; }
	void set_plane(const unsigned char *plane, int width, int height);
	Palette* get_palette()
		{ return this->palette; }
	void set_palette(Palette *palette)
		{ this->palette = palette; }
	void close()
		{ if (this->planes != NULL) delete [] this->planes; }
};